import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import seaborn as sns
from sklearn import datasets
from sklearn import manifold

'''
使用 sklearn 提供的内置函数来获取 MNIST 数据集
fetch_openml 是 scikit-learn 库中的一个函数，用于从 OpenML 数据集存储库中获取数据集。
return_X_y 用于指定是否返回特征数据和目标标签。
当 return_X_y 参数设置为 True 时，fetch_openml 函数将仅返回特征数据和目标标签，而不会返回其他元数据。
其中特征数据常用来做驯良，目标标签用来做测试
'''
data = datasets.fetch_openml(
    'mnist_784',
    version=1,
    return_X_y=True
)
pixel_values, targets = data
targets = targets.astype(int)

single_image = pixel_values.iloc[1, :].to_frame().values.reshape(28, 28)
# 展示图片
plt.imshow(single_image, cmap='gray')
plt.show()

'''
t-SNE（t-distributed Stochastic Neighbor Embedding）是一种流形学习技术，用于降低高维数据的维度，
以便可视化和发现数据中的结构。其主要思想是将高维空间中的相似性映射到低维空间中，同时尽可能保持数据点之间的局部关系。
在进行 t-SNE 转换时，需要指定一些参数，最常用的是：
    n_components：指定转换后的特征空间的维度数。
    perplexity：影响 t-SNE 模型选择局部近邻的数量，通常设置在5到50之间。
    learning_rate：学习率，控制数据点在嵌入空间中移动的速度。
    
转换后的数据可以用于可视化，通常使用散点图来展示降维后的数据点，以便观察数据之间的聚类结构和分布情况。
'''

# 创建 TSNE 模型并指定参数
tsne = manifold.TSNE(n_components=2, random_state=42)
# 对数据进行 t-SNE 转换
transformed_data = tsne.fit_transform(pixel_values.iloc[:3000, :].values)

'''
    np.column_stack 的作用是将多个一维数组沿着列方向进行堆叠，生成一个新的二维数组。
    如果输入的数组维度不同，它会先尝试将这些数组转换为相同的维度，然后再进行堆叠。
    例如：
    import numpy as np

    # 创建两个一维数组
    array1 = np.array([1, 2, 3])
    array2 = np.array([4, 5, 6])
    
    # 使用 np.column_stack 将这两个数组按列堆叠
    result = np.column_stack((array1, array2))
    print(result)
    输出：
        [[1 4]
         [2 5]
         [3 6]]

'''
tsne_df = pd.DataFrame(
    np.column_stack((transformed_data, targets[:3000])),
    columns=["x", "y", "targets"]
)
tsne_df.loc[:, "targets"] = tsne_df.targets.astype(int)
print(tsne_df)

grid = sns.FacetGrid(tsne_df, hue="targets")
grid.map(plt.scatter, "x", "y")
plt.show()
# This is one way of visualizing unsupervised datasets.

